!(
   function F(str, ...) return string.format(str, ...) end
   
   function EQ(...)
      local out_str = ""
      local len = select("#", ...)
      assert(len > 1, "not enough arguments for EQ macro")
      for i=1, len do
	 local var = select(i, ...)
	 if i+1 <= len then
	    local var2 = select(i+1, ...)
	    if i == 1 then
	       out_str = F("((%s == %s)", var, var2)
	    else
	       out_str = F("%s and (%s == %s)", out_str, var, var2)
	    end
	 end
      end
      return out_str .. ")"
   end

   function TRACE (s)
      assert(s ~= nil, "TRACE: no arguments given")
      return F([[
pl.pretty.dump(debug.getinfo(1))
local time_before = os.time()
%s
print(string.format ("time taken: %%f s", os.difftime(os.time(), time_before)))
]], s)
   end

   function NEW_TABLE(...)
      local out_str = ""
      for i=1, select("#", ...) do
	 local t = select(i, ...)
	 out_str = F("%s\nlocal %s = {}", out_str, t)
      end
      return out_str
   end

   function NEW_G_TABLE(...)
      local out_str = ""
      for i=1, select("#", ...) do
	 local t = select(i, ...)
	 out_str = F("%s\n%s = {}", out_str, t)
      end
      return out_str
   end

   function EXTEND(t, exttbl)
      return F("lume.extend(%s, %s)", t, exttbl)
   end

   function INC(v, n)
      return F("%s = %s + %s", v, v, n)
   end

   function RSZ(v, n)
      return F("%s = %s * %s", v, v, n)
   end
   
   function SWITCH(var, ...)
      --[[ USAGE: @@SWITCH(a, 
	 1: return 2
	 2: return 5
	 )
	 => if a == 1 then return 2 end; if a == 2 then return 5 end
      ]]
      
      local out_str = ""
      for i=1, select("#", ...)  do
	 local s = select(i, ...)
	 local cond_val, func = string.match(s, "([%w%(%)%s%.]+):%s+(.+)")
	 out_str = out_str .. F("if %s == %s then %s end", var, cond_val, func) .. "\n"
      end
      return out_str
   end

   function COND(...)
      --[[ 
	 USAGE: @@COND(                if a then do_this()
	 a: do_this()          =>      elseif b then do_that()
	 b: do_that())                 end
	 
      ]]
      local out_str = ""
      for i=1, select("#", ...) do
	 local s = select(i, ...)
	 local _if = (i == 1) and 'if' or 'elseif'
	 local cond_val, func = string.match(s, "([%S%s]*):%s+(.+)")
	 assert(cond_val and func, "bad @@COND arguments")
	 out_str = F("%s\n%s %s then %s", out_str, _if, cond_val, func)
      end
      out_str = F("%s\nend", out_str)
      return out_str
   end

   function WHEN(...)
      --[[ 
	 USAGE: @@WHEN(                if a then do_this()
	 a: do_this()          =>      if b then do_that()
	 b: do_that())                 end
	 
      ]]
      local out_str = ""
      for i=1, select("#", ...) do
	 local s = select(i, ...)
	 local cond_val, func = string.match(s, "([%S%s]*):%s+(.+)")
	 assert(cond_val and func, "bad @@WHEN arguments")
	 out_str = F("%s\nif %s then %s end", out_str, cond_val, func)
      end
      return out_str
   end

   function REST(table)
      return F("lume.slice(%s, 2)", table)
   end

   function EACH(table, chunk)
      return F("lume.each(%s, function (v) %s end)", table, chunk)
   end

   function REDUCE(table, chunk)
      return F("lume.reduce(%s, function (u, v) %s end)", table, chunk)
   end

   function VARARG_EACH(chunk)
      local out_str = ""
      return F([[
for i=1, select('#', ...) do
local v = select(i, ...)
%s
end
]], chunk)
   end

   function MAP(table, chunk)
      return F("lume.map(%s, function (v) %s end)", table, chunk)
   end
   
   function ALL(table, cond)
      return F("lume.all(%s, function (v) return %s end)", table, cond)
   end

   function ANY(table, cond)
      return F("lume.any(%s, function (v) return %s end)", table, cond)
   end

   function INC(var, increment)
      return F("%s = %s + %s", var, var, increment)
   end

   function MATCH(table, cond)
      return F("lume.match(%s, function (v) return %s end)", table, cond)
   end

   function GEN(fd, file)
      return F("'%s.gen.%s'", fd, file)
   end

   function SFN(name, ...)
      local out_str = F("%s = function (self ", name)
      local len = select("#", ...)
      for i=1, select("#", ...) - 1 do
	 local v = select(i, ...)
	 out_str = F("%s, %s", out_str, v)
      end
      local chunk = select(len, ...)
      return F("%s)\n%s\nend", out_str, chunk)
   end

   function CLASS(cls_name, ...)
      local arg_str = ""
      if select(1, ...) == "#noinit" then
	 return F ("Class{_name = %s,}", cls_name)
      end
      local regexp = "([%a_]+)%s*=?%s*([%s%S]*)"
      for _, v in ipairs{...} do
	 local sep
	 -- default value?
	 local vname, defval = string.match(v, regexp)
	 assert(vname, "no var given")
	 if _ <= #{...} then sep = ", " else sep = "" end
	 arg_str = arg_str .. sep .. vname
      end
      local arg_decl_str = ""
      for _, v in ipairs{...} do
	 if _ < #{...} then sep = "\n" else sep = "" end
	 local vname, defval = string.match(v, regexp)
	 local dstr
	 if defval == "" or defval == nil then
	    dstr = F("self.%s = %s", vname, vname)
	 else
	    dstr = F("self.%s = %s or %s", vname, vname, defval)
	 end
	 arg_decl_str = arg_decl_str .. dstr   .. sep
      end
      
      return F ([[
Class{
_name = %s,
init = function (self %s)
%s
end
}
]], cls_name, arg_str, arg_decl_str)
   end

   function SUBCLASS(subcls, cls_name, ...)
      --TODO
   end

   hex2rgb = function (hex)
      local hex = hex:gsub("#","")
      if hex:len() == 3 then
	 return (tonumber("0x"..hex:sub(1,1))*17)/255,
	    (tonumber("0x"..hex:sub(2,2))*17)/255, (tonumber("0x"..hex:sub(3,3))*17)/255
      else
	 return tonumber("0x"..hex:sub(1,2))/255,
	    tonumber("0x"..hex:sub(3,4))/255, tonumber("0x"..hex:sub(5,6))/255
      end
   end

   function SET_CL(r, g, b, a)
      return F("love.graphics.setColor(%s, %s, %s, %s)", r, g, b, a or "1")
   end
   
   function SET_HEX_CL(hex, a)
      local r, g, b = hex2rgb(hex)
      return F("love.graphics.setColor(%s, %s, %s, %s)", r, g, b, a or "1")
   end

   function CL_RESET() return SET_HEX_CL("#FFFFFF") end

   function WITH_COLOR(hex, chunk)
      return F("%s\n%s\n%s", SET_HEX_CL(hex), chunk, CL_RESET())
   end

   function RECT(x, y, w, h, fill, color)
      local mode
      if tostring(fill) == 'nil' then
	 mode = 'line'
      else
	 mode = 'fill'
      end
      
      local draw_str = F("love.graphics.rectangle('%s', %s, %s, %s, %s)", mode, x, y, w, h)
      if not color then
	 return draw_str
      else
	 return WITH_COLOR(color, draw_str)
      end
   end

   LW = "love.window"
   LG = "love.graphics"
   LF = "love.filesystem"
   LM = "love.mouse"
   LK = "love.keyboard"

   function lib (path)
      return F("require('lib.%s')", path)
   end

   function src (path)
      return F("require('src.gen.%s')", path)
   end

   function ui (path)
      return F("require('ui.%s')", path)
   end

   function states (path)
      return F("require('states.gen.%s')", path)
   end

 )
